package com.gerfmarquez.nymph.music.core;

import java.util.ArrayList;
import java.util.concurrent.ConcurrentLinkedQueue;

import android.app.Activity;
import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Handler;
import android.widget.Button;

import com.gerfmarquez.nymph.R;
import com.gerfmarquez.nymph.ui.seekbar.ActiveSeekBarMusicNote;
import com.gerfmarquez.nymph.ui.threads.UpdatePlayStateNotesThread;

public class PlayNotesThread extends Thread {
	
	 int noteType;
	 static final String TAG= "PlayNotesThread";
	 byte[][] NOTES;
	 byte[] rhythms;
	 int[] millis;
	 UpdatePlayStateNotesThread uPSN;
	 Handler updatePlayStateNotesHandler;
//	 byte []silence = new byte[5000];
	 public boolean played = false;
	 Activity activity;
   	 
     int minBuffSize = AudioTrack.getMinBufferSize(MusicCore.SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_8BIT);
     AudioTrack audioTrack = new AudioTrack( AudioManager.STREAM_MUSIC,  MusicCore.SAMPLE_RATE,
    		 AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_8BIT,
 			minBuffSize, AudioTrack.MODE_STREAM);
     
//   	 This constructor will probably be removed because it's not needed.
//   	 public PlayNotesThread(int noteType, ArrayList<AudioTrack> audioTracks, byte[][] notesToPlay) {
//		    audioTrack = new AudioTrack( AudioManager.STREAM_MUSIC,  44100,
//		    		AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_8BIT,
//					minBuffSize, AudioTrack.MODE_STREAM);
//		 audioTracks.add(audioTrack);
//   		 android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
//   		 this.noteType = noteType;
//   		NOTES = notesToPlay;
//   		 Log.d(TAG, "Min Buffer size is "+minBuffSize);
//		}
   	 public PlayNotesThread(byte[] rhythmsToPlay, ArrayList<AudioTrack> audioTracks, byte[][] notesToPlay, UpdatePlayStateNotesThread uPSN, final Activity activity) {
   		 this.uPSN = uPSN;
   		updatePlayStateNotesHandler = uPSN.getActiveNoteChanger();
   		 audioTrack = new AudioTrack( AudioManager.STREAM_MUSIC,  MusicCore.SAMPLE_RATE,
   				AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_8BIT,
   				 minBuffSize, AudioTrack.MODE_STREAM);
   		 audioTracks.add(audioTrack);
   		 NOTES = notesToPlay;
//   		 Log.d(TAG, "Min Buffer size is "+minBuffSize);
   		rhythms = rhythmsToPlay; 
//   		for(int i = 0; i<silence.length; i++) {
//   			silence[i] = MusicCore.SILENCE_PCM;
//   		}
   		this.activity = activity;
   	 }
   	
   	public void run() {
   		android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO);
   		
   		byte[]  audByte;
//   		int noteRhythm = noteType;
   		int songArrayIndex = 0;
//   		int compass = 3;
//   		int numberOfCompasses = 3;
   		
   		int bytesToWriteWithBPMinTotal = 0;
   		int totalBytes;
   		int bytesPerNoteAccumulated[] = new int[rhythms.length+1];
   		ArrayList<Integer> bytesPerNoteAccumulated2 = new ArrayList<Integer>();
   		bytesPerNoteAccumulated2.add(0);
   		bytesPerNoteAccumulated[0] = 0;
   		millis = new int[rhythms.length];
		for(int i= 1; i<rhythms.length+1;i++) {
			int bytesOnThisNote = MusicCore.cutLength(rhythms[i-1]);
			int currentMmillis = MusicCore.getMillisFromBytes(bytesOnThisNote);
			bytesToWriteWithBPMinTotal += bytesOnThisNote;
			bytesPerNoteAccumulated[i] = bytesOnThisNote+bytesPerNoteAccumulated[i-1];
			bytesPerNoteAccumulated2.add(bytesOnThisNote+bytesPerNoteAccumulated2.get(i-1));
			millis[i-1] = currentMmillis;
			
			
//			Log.d(TAG,"Rhythm :"+i+" length "+rhythms[i-1]);
		}
		totalBytes = bytesToWriteWithBPMinTotal;
//   		}
   		AudioTrack aud = audioTrack;
   		int currentNote = 0;
   		byte []songArray = null;
//   		Log.d(TAG, "Total songArrayBytes = " + totalBytes);
   		songArray = new byte[totalBytes];
   		for (int i = 0; i< NOTES.length; i++) {
   			int rhythm = 0;
   			if(rhythms != null) {
   				rhythm = rhythms[i];
   			}
   			else {
   				rhythm = noteType;
   			}
   			int bytesToWriteWithBPMperNote = MusicCore.cutLength(rhythm);
   			audByte =  NOTES[i];
   		
//   			Log.d(TAG, "Note number: "+i+" ");
   				
				songArray = MusicCore.append(songArray, audByte, songArrayIndex,bytesToWriteWithBPMperNote);
				songArrayIndex += bytesToWriteWithBPMperNote;
				
//   			Log.d(TAG, "Bytes to write with bpm : " +bytesToWriteWithBPMperNote);
   		}
   		
//   		Log.d(TAG, "play back state is: " +aud.getPlayState());
   		aud.play();
//   		Log.d(TAG, "play back state is: " +aud.getPlayState());
   		final ConcurrentLinkedQueue<ActiveSeekBarMusicNote> activeMusicNoteQueue = new ConcurrentLinkedQueue<ActiveSeekBarMusicNote>();
   		
   		int currentTempBuffIndex =  0;
   		while(currentTempBuffIndex < songArray.length) {
				byte[] tempBuff = new byte[minBuffSize];
				int i = 0;
				minBufferLoop:
				for(; i<minBuffSize; i++,currentTempBuffIndex++) {
					if(currentTempBuffIndex >= songArray.length) {
						break minBufferLoop;
					}
					tempBuff[i] = songArray[currentTempBuffIndex];
					Integer current = new Integer(currentTempBuffIndex);
					if(bytesPerNoteAccumulated2.contains(current)) {
						bytesPerNoteAccumulated2.remove(current);
						ActiveSeekBarMusicNote aSBMN = new ActiveSeekBarMusicNote();
						aSBMN.setIndex(currentNote);
						aSBMN.setMillis(millis[currentNote]);
						activeMusicNoteQueue.offer(aSBMN);
						currentNote++;
					}
				}
   			aud.write(tempBuff, 0, i);
   			Runnable runnable = new Runnable() {
   				public void run() {
   					updatePlayStateNotesHandler.post(new Runnable() {
   						
   						@Override
   						public void run() {
   							uPSN.changeToPlayState(activeMusicNoteQueue, rhythms.length);
   						}
   					});
   				}
   			};
   			new Thread(runnable).start();
   		}
   		uPSN.setAllViewsProcessed(true);
   		updatePlayStateNotesHandler.post(new Runnable() {
   			
   			@Override
   			public void run() {
   				uPSN.updateLast();
   		   		Button playButton = (Button)activity.findViewById(R.id.playButton);
   		   		playButton.setEnabled(true);
   			}
   		});
//   		Log.d(TAG, "play back state is: " +aud.getPlayState());
//   		aud.write(silence, 0, silence.length);
//   		try {
//			Thread.sleep(5000);
//		} catch (InterruptedException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}

   		aud.release();
   		played = true;
   	}
   	
//   	private boolean isNoteinIndex(int currentTempBuffIndex, int[] bytesPerNoteAccumulated) {
//   		for(int i = 0; i<bytesPerNoteAccumulated.length; i++) {
//   			if(currentTempBuffIndex == bytesPerNoteAccumulated[i]) {
//   				return true;
//   			}
//   		}
//   		return false;
//   	}
}
